package com.agentfactory.teleoreactive.interpreter;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Observable;

import com.agentfactory.logic.update.lang.IFormula;
import com.agentfactory.logic.update.lang.ITerm;
import com.agentfactory.logic.update.lang.Predicate;
import com.agentfactory.logic.update.reasoner.IQueryEngine;
import com.agentfactory.logic.update.reasoner.ResolutionBasedQueryEngine;
import com.agentfactory.platform.impl.AbstractAgent;
import com.agentfactory.teleoreactive.interpreter.mentalstate.Action;
import com.agentfactory.teleoreactive.interpreter.mentalstate.ModelTower;
import com.agentfactory.teleoreactive.interpreter.mentalstate.PerceptionTower;
import com.agentfactory.teleoreactive.interpreter.mentalstate.Sensor;
import com.agentfactory.teleoreactive.interpreter.mentalstate.TRProgram;

public abstract class AbstractTeleoReactiveAgent extends AbstractAgent {
	protected ModelTower beliefs;
	protected PerceptionTower rules;
	protected IQueryEngine engine;
	protected Map<String, TRProgram> programs;
	protected Map<String, Action> actionMap;
	protected Map<String, Sensor> sensorMap;
	protected String activeProgram;
	protected List<String> programStack;
	protected List<String> actionTrace;

	public AbstractTeleoReactiveAgent(String name) {
		super(name);
		actionTrace = new LinkedList<String>();
		beliefs = new ModelTower();
		rules = new PerceptionTower();
		engine = new ResolutionBasedQueryEngine();
		engine.addSource(beliefs);
//		engine.addSource(rules);
//		engine.
		activeProgram = "main:0";
		programs = new HashMap<String, TRProgram>();
		actionMap = new HashMap<String, Action>();
		sensorMap = new HashMap<String, Sensor>();
		programStack = new LinkedList<String>();
		actionTrace = new LinkedList<String>();
	}

	@Override
	public void execute() {
		beliefs.clearTower();
		for (Sensor sensor : sensorMap.values()) {
			sensor.perceive();
//			System.out.println(beliefs.toString());
		}
		IFormula activity = programs.get(activeProgram).execute(engine,	new LinkedList<ITerm>());
//		System.out.println("Executed method "+Utilities.presenter.toString((Predicate) activity));
	    while (programs.containsKey(Utilities.createSignature((Predicate) activity))) {
	    	programStack.add(Utilities.presenter.toString(activity));
//	    	System.out.print("Potential Action..."+((Predicate) activity).functor() + " with args ");
//	    	for (int i = 0; i < ((Predicate)activity).size(); i++) {
//	    		System.out.print(Utilities.presenter.toString(((Predicate)activity).termAt(i)));
//	    	}
//	    	System.out.println();
			if (Predicate.class.isInstance(activity)) {
				Predicate potentialAction = ((Predicate) activity);
				LinkedList<ITerm> args = new LinkedList<ITerm>();
				for (int i = 0; i < potentialAction.size(); i++) {
					args.add(i, potentialAction.termAt(i));
				}
				activity = programs.get(Utilities.createSignature((Predicate) activity)).execute(engine, args);
				if(programs.containsKey(Utilities.createSignature((Predicate) activity)))
					System.out.println("Executed method "+Utilities.presenter.toString((Predicate) activity));
			}
		}
		performActivity((Predicate) activity);
		endOfIteration();
	}

	public String getType() {
		return "AF-TeleoReactive";
	}

	public boolean performActivity(Predicate activity) {
		Action action = actionMap.get(Utilities.createSignature(activity));
		if (action == null) {
			return false;
		}
		boolean s = action.execute(activity);
		if(s) actionTrace.add(actionTrace.size(), Utilities.presenter.toString(activity));
		return s;
	}

	@Override
	public void initialise(String data) {
		if(data.startsWith("action(")){
			data = data.substring(7, data.length()-1);
		IFormula act = Utilities.factory.createFormula(data);
		if(Predicate.class.isInstance(act))
			performActivity((Predicate)act);
		} else if(data.startsWith("belief(")){
			data = data.substring(7, data.length()-1);
			IFormula act = Utilities.factory.createFormula(data);
			if(Predicate.class.isInstance(act))
				addBelief((Predicate)act);
		}
		// TODO Auto-generated method stub

	}

	@Override
	public void update(Observable o, Object arg) {
		// TODO Auto-generated method stub

	}

	public void addBelief(Predicate formula) {
		beliefs.addBelief(formula);
	}

	public List<String> getStack(){
		List<String> s = new LinkedList<String>();
		for (String string : programStack) {
	        s.add(string);
        }
		
		programStack.clear();
		return s;
	}
	
	public List<String> getBeliefs(){
		return beliefs.getBeliefs();
	}
	public List<String> getActionTrace(){
		List<String> n = new LinkedList<String>();
		for(String s: actionTrace){
			n.add(s);
		}
		return n;
	}
}
